package com.example.aop.aspect;

import com.example.aop.annotation.Log;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import sun.net.util.IPAddressUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

/**
 * @author: qilongxin
 * @date: 2021/8/13 14:40
 */
@Aspect
@Component
@Slf4j
public class WebLogAspect {

    /**
     * execution 拦截里面的正则匹配的方法;
     * ＊ 匹配任意返回类型的方法;
     * (..) 匹配任意类型参数;
     */

//     @Pointcut("execution( * com.example.aop.service.impl.*.*(..)) && @annotation(com.example.aop.annotation.Log)")
//     public void logPointCut() {}

    @Pointcut("execution( * com.example.aop.service.impl.HelloServiceImpl.sayHello(..))")
    public void logPointCut() {}

//      @Pointcut("execution( * com.example.aop.service.impl.TestServiceImpl.sayHello(..))")
//      public void logPointCut() {}

//    @Pointcut("@annotation(com.example.aop.annotation.Log)")
//    public void logPointCut() {}

    @Around("@annotation(logger)")
    public Object doAround(ProceedingJoinPoint pjp, Log logger) throws Throwable {
        long startTime = System.currentTimeMillis();
        log.info("[Around start]: " + pjp.getSignature());
        // 回调目标对象的原有方法
        Object object = pjp.proceed();
        log.info(logger.value() + logger.annotationType());
        log.info("[Around end]: " + pjp.getSignature());
        log.info("耗时 : " + (System.currentTimeMillis() - startTime));
        return object;
    }

    @Before("logPointCut()")
    public void doBefore(JoinPoint joinPoint) {
        // 获取请求request
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
        log.info("---方法开始执行---");
        log.info("请求地址 : " + request.getRequestURL().toString());
        log.info("HTTP METHOD : " + request.getMethod());
        log.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        log.info("传入的参数 : " + Arrays.toString(joinPoint.getArgs()));
    }

    @After("logPointCut()")
    public void doAfter() {
        log.info("---方法执行完毕---");
    }

    @AfterReturning(pointcut = "logPointCut()", returning = "afterReturn")
    public void doAfterReturning(Object afterReturn) {
        // 处理完请求返回的内容
        log.info("连接点方法返回值：" + afterReturn);
    }

    @AfterThrowing(pointcut = "logPointCut()", throwing = "afterThrow")
    public void doAfterThrowing(Throwable afterThrow) {
        log.info("连接点方法异常：" + afterThrow);
    }
}
